﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.IO;
using System.Drawing;
using System.Drawing.Imaging;
using _2009035.Models;
using _2009035.Helpers;

namespace _2009035.Controllers
{
    //[RequireHttps]
    public class ImageController : Controller
    {
        private DbEntities db = new DbEntities();

        #region static variables

        private static string ImageCacheKey = "ImageKey_";
        private static int W_FixedSize = 200;
        private static int H_FixedSize = 200;
        private string workingImageId = "{0}-Original";
        private string modifiedImageId = "{0} modified";
        byte[] workingImage;
        byte[] modifiedImage;

        #endregion
        
        #region session properties

        private string WorkingImageId
        {
            get
            {
                return string.Format(workingImageId, User.Identity.Name);
            }
            set { workingImageId = value; }
        }

        private string ModifiedImageId
        {
            get
            {
                return string.Format(modifiedImageId, User.Identity.Name); 
            }
            set { modifiedImageId = value; }
        }

        private string WorkingImageExtension { get; set; }

        #endregion

        #region cached properties

        private byte[] WorkingImage
        {
            get
            {

                var path = Path.Combine(Server.MapPath("/Images"), string.Format("{0}.{1}", WorkingImageId, "jpg"));

                // Load file meta data with FileInfo
                FileInfo fileInfo = new FileInfo(path);

                // The byte[] to save the data in
                byte[] data = new byte[fileInfo.Length];

                // Load a filestream and put its content into the byte[]
                using (FileStream fs = fileInfo.OpenRead())
                {
                    fs.Read(data, 0, data.Length);
                }

                // Delete the temporary file
                //fileInfo.Delete();


                return data;
            }

            set { workingImage = value; }
        }

        private byte[] ModifiedImage
        {
            get
            {

                var path = Path.Combine(Server.MapPath("/Images"), string.Format("{0}.{1}", ModifiedImageId, "jpg"));

                // Load file meta data with FileInfo
                FileInfo fileInfo = new FileInfo(path);

                // The byte[] to save the data in
                byte[] data = new byte[fileInfo.Length];

                // Load a filestream and put its content into the byte[]
                using (FileStream fs = fileInfo.OpenRead())
                {
                    fs.Read(data, 0, data.Length);
                }

                // Delete the temporary file
                // fileInfo.Delete();


                return data;
            }

            set { modifiedImage = value; }

        }

        #endregion

        private enum ImageModificationType
        {
            Crop,
            Resize
        };

        /// <summary>
        /// Files the upload.
        /// </summary>
        /// <param name="uploadedFileMeta">The uploaded file meta.</param>
        /// <returns></returns>
        //[Authorize]
        public ActionResult FileUpload(MediaAssetUploadModel uploadedFileMeta)
        {
            var name = User.Identity.Name;
            string newImageId = string.Empty;
            try
            {
                newImageId = ProcessUploadedImage(uploadedFileMeta);
            }
            catch (Exception ex)
            {
                string errorMsg = string.Format("Error processing image: {0}", ex.Message);
                Response.StatusCode = 500;
                Response.Write(errorMsg);
                return Json(string.Empty);
            }

            return Json(new { Id = newImageId, Status = "OK" });
        }

        /// <summary>
        /// Processes the uploaded image.
        /// </summary>
        /// <param name="uploadedFileMeta">The uploaded file meta.</param>
        /// <returns>Image Id</returns>
        private string ProcessUploadedImage(MediaAssetUploadModel uploadedFileMeta)
        {
            // Get the file extension
            WorkingImageExtension = Path.GetExtension(uploadedFileMeta.Filename).ToLower();
            string[] allowedExtensions = { ".png", ".jpeg", ".jpg", ".gif" }; // Make sure it is an image that can be processed
            if (allowedExtensions.Contains(WorkingImageExtension))
            {
                // WorkingImageId = Guid.NewGuid();
                Image workingImageMAP = new Bitmap(uploadedFileMeta.fileData.InputStream);
                workingImage = ImageHelper.ImageToByteArray(workingImageMAP);
                var path = Path.Combine(Server.MapPath("/Images"), string.Format("{0}{1}", WorkingImageId, WorkingImageExtension));
                System.Diagnostics.Debug.WriteLine(path);
                var fs = new BinaryWriter(new FileStream(path, FileMode.Create, FileAccess.Write));
                fs.Write(workingImage);
                fs.Close();
            }
            else
            {
                throw new Exception("Cannot process files of this type.");
            }

            return WorkingImageId;
        }

        /// <summary>
        /// Crops the image.
        /// </summary>
        /// <param name="x">The x.</param>
        /// <param name="y">The y.</param>
        /// <param name="w">The w.</param>
        /// <param name="h">The h.</param>
        /// <returns>Image Id</returns>
        public JsonResult CropImage(int x, int y, int w, int h)
        {
            try
            {
                if (w == 0 && h == 0) // Make sure the user selected a crop area
                    throw new Exception("A crop selection was not made.");

                string imageId = ModifyImage(x, y, w, h, ImageModificationType.Crop);
                return Json(imageId);
            }
            catch (Exception ex)
            {
                string errorMsg = string.Format("Error cropping image: {0}", ex.Message);
                Response.StatusCode = 500;
                Response.Write(errorMsg);
                return Json(string.Empty);
            }
        }

        /// <summary>
        /// Resizes the image.
        /// </summary>
        /// <returns>Image Id</returns>
        public JsonResult ResizeImage()
        {
            try
            {
                string imageId = ModifyImage(0, 0, W_FixedSize, H_FixedSize, ImageModificationType.Resize);
                return Json(imageId);
            }
            catch (Exception ex)
            {
                string errorMsg = string.Format("Error resizing image: {0}", ex.Message);
                Response.StatusCode = 500;
                Response.Write(errorMsg);
                return Json(string.Empty);
            }
        }

        /// <summary>
        /// Modifies an image image.
        /// </summary>
        /// <param name="x">The x.</param>
        /// <param name="y">The y.</param>
        /// <param name="w">The w.</param>
        /// <param name="h">The h.</param>
        /// <param name="modType">Type of the mod. Crop or Resize</param>
        /// <returns>New Image Id</returns>
        private string ModifyImage(int x, int y, int w, int h, ImageModificationType modType)
        {
            Image img = ImageHelper.ByteArrayToImage(WorkingImage);

            using (System.Drawing.Bitmap _bitmap = new System.Drawing.Bitmap(w, h))
            {
                _bitmap.SetResolution(img.HorizontalResolution, img.VerticalResolution);
                using (Graphics _graphic = Graphics.FromImage(_bitmap))
                {
                    _graphic.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
                    _graphic.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
                    _graphic.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.HighQuality;
                    _graphic.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;

                    if (modType == ImageModificationType.Crop)
                    {
                        _graphic.DrawImage(img, 0, 0, w, h);
                        _graphic.DrawImage(img, new Rectangle(0, 0, w, h), x, y, w, h, GraphicsUnit.Pixel);
                    }
                    else if (modType == ImageModificationType.Resize)
                    {
                        _graphic.DrawImage(img, 0, 0, img.Width, img.Height);
                        _graphic.DrawImage(img, new Rectangle(0, 0, W_FixedSize, H_FixedSize), 0, 0, img.Width, img.Height, GraphicsUnit.Pixel);
                    }

                    //string extension = WorkingImageExtension;

                    //// If the image is a gif file, change it into png
                    //if (extension.EndsWith("gif", StringComparison.OrdinalIgnoreCase))
                    //{
                    //    extension = ".png";
                    //}

                    using (EncoderParameters encoderParameters = new EncoderParameters(1))
                    {
                        encoderParameters.Param[0] = new EncoderParameter(Encoder.Quality, 100L);
                        modifiedImage = ImageHelper.ImageToByteArray(_bitmap, ".jpg", encoderParameters);
                        var path = Path.Combine(Server.MapPath("/Images"), string.Format("{0}.{1}", ModifiedImageId, "jpg"));
                        var fs = new BinaryWriter(new FileStream(path, FileMode.Create, FileAccess.Write));
                        fs.Write(modifiedImage);
                        fs.Close();
                    }
                }
            }

            return ModifiedImageId.ToString();
        }

        /// <summary>
        /// Shows the specified id.
        /// </summary>
        /// <param name="id">The id.</param>
        /// <returns>
        /// The existing image of the user that has been stored in the DB
        /// if the user does not have an image, the default image is shown
        /// </returns>
        public ActionResult Show(int id=0)
        {
            int employeeNumber;
            if (id > 0)
            {
                employeeNumber = id;
            }
            else
            {
                int.TryParse(User.Identity.Name, out employeeNumber);
            }
           
              
                EmployeeImage dbImage = null;
                FileContentResult result = null;
                try
                {
                    // check if there are items in the employee images table
                    if (db.EmployeeImages.Count() > 0)
                    {
                        if (db.EmployeeImages.Where(x => x.employeeNumber == employeeNumber).Count() > 0)
                        {
                            dbImage = db.EmployeeImages.First(x => x.employeeNumber == employeeNumber);      
                        }
                                        
                    }

                    if (dbImage == null)
                    {
                        var path = Path.Combine(Server.MapPath("~/Content/images"), string.Format("user.png"));

                        // Load file meta data with FileInfo
                        FileInfo fileInfo = new FileInfo(path);

                        // The byte[] to save the data in
                        byte[] data = new byte[fileInfo.Length];

                        // Load a filestream and put its content into the byte[]
                        using (FileStream fs = fileInfo.OpenRead())
                        {
                            fs.Read(data, 0, data.Length);
                        }

                        // Delete the temporary file
                        //fileInfo.Delete();

                        result = new FileContentResult(data, "image/png");

                    }
                    else
                    {
                        result = new FileContentResult(dbImage.image, "image/jpg");
                    }

                    return result;

                }
                catch (Exception ex)
                {

                    throw;
                }
            
            return null;
        }

        public ActionResult SaveImage()
        {          
            EmployeeImage newEmployeeImage = new EmployeeImage();
            newEmployeeImage.employeeNumber = int.Parse(User.Identity.Name);


            if (ModifiedImage != null)
            {
                newEmployeeImage.image = ModifiedImage;
            }
            else if (WorkingImage != null)
            {
                newEmployeeImage.image = WorkingImage;
            }

            if (newEmployeeImage.image != null)
            {
                var tempEmp = db.EmployeeImages.FirstOrDefault(x => x.employeeNumber == newEmployeeImage.employeeNumber);
                if (tempEmp != null)
                {
                    tempEmp.image = newEmployeeImage.image;
                }
                else
                {
                    db.EmployeeImages.Add(newEmployeeImage);
                }

                db.SaveChanges();
                return Json("Success");
            }
            else
            {
                return Json("Fail");
            }
        }

    }
}
